import cv2
import numpy as np
import matplotlib.pyplot as plt

filename = 'img/opencv_logo.png'


def getImg():
    return cv2.imread(filename)


# 使用Matplotlib显示图像
def matplotlibShowImg(title, image):
    plt.title(title)
    plt.imshow(image, interpolation='bicubic')
    plt.xticks([]), plt.yticks([])  # 隐藏坐标轴刻度
    plt.show()


def fileImg(src, filp_code):
    '图像翻转, flip_code==0垂直翻转, >0水平翻转, <0水平+垂直翻转'
    if filp_code == 0:
        return src[::-1]
    elif filp_code > 0:
        return src[:, ::-1]
    else:
        return src[::-1, ::-1]


def resizeImg(src, dsize):
    sh, sw = src.shape[0], src.shape[1]
    dh, dw = dsize[0], dsize[1]
    # 定义目标图像
    if len(src.shape) == 3:
        dst = np.zeros((dh, dw, src.shape[-1]), dtype=np.uint8)
    else:
        dst = np.zeros((dh, dw), dtype=np.uint8)
    # 计算缩放比例的倒数
    fx = src.shape[1] / dw
    fy = src.shape[0] / dh
    # 填充目标图像
    for i in range(dh):
        iy = round(fy * i)
        if iy >= sh: iy = sh - 1
        for j in range(dw):
            jx = round(fx * j)
            if jx >= sw: jx = sw - 1
            dst[i][j] = src[iy][jx]

    return dst


def image_rotate(src, angle):
    sh, sw = src.shape[0], src.shape[1]
    angle = angle * np.math.pi / 180.0
    sina = np.math.sin(angle)
    cosa = np.math.cos(angle)
    # 计算旋转后图像坐标
    pts = [[0, sh], [sw, sh], [sw, 0]]
    min_dx = max_dx = min_dy = max_dy = 0
    for pt in pts:
        x = round(cosa * pt[0] - sina * pt[1])
        y = round(sina * pt[0] + cosa * pt[1])
        if x < min_dx: min_dx = x
        if x > max_dx: max_dx = x
        if y < min_dy: min_dy = y
        if y > max_dy: max_dy = y
        # 定义目标图像
        dh = max_dy - min_dy + 1
    dw = max_dx - min_dx + 1
    if len(src.shape) == 3:
        dst = np.zeros((dh, dw, src.shape[-1]), dtype=np.uint8)
    else:
        dst = np.zeros((dh, dw), dtype=np.uint8)
    # 填充目标图像
    for i in range(dh):
        for j in range(dw):
            y, x = i + min_dy, j + min_dx
            iy = round(-sina * x + cosa * y)
            jx = round(cosa * x + sina * y)
            if 0 <= iy < sh and 0 <= jx < sw:
                dst[i][j] = src[iy][jx]
    return dst


# 利用cv.warpAffine进行图像旋转, 绕左上角逆时针旋转, angle为旋转角(角度)
def cv_image_rotate(src, angle):
    sh, sw = src.shape[0], src.shape[1]
    angle = angle * np.math.pi / 180.0
    sina = np.math.sin(angle)
    cosa = np.math.cos(angle)
    # 计算旋转后图像坐标
    pts = [[0, sh], [sw, sh], [sw, 0]]
    min_dx = max_dx = min_dy = max_dy = 0
    for pt in pts:
        x = round(cosa * pt[0] - sina * pt[1])
        y = round(sina * pt[0] + cosa * pt[1])
        if x < min_dx: min_dx = x
        if x > max_dx: max_dx = x
        if y < min_dy: min_dy = y
        if y > max_dy: max_dy = y
        # 定义目标图像
        dh = max_dy - min_dy + 1
    dw = max_dx - min_dx + 1
    M = np.float32([[cosa, -sina, -min_dx],
                    [sina, cosa, -min_dy]])
    dst = cv2.warpAffine(src, M, (dw, dh))
    return dst


def center_rotate(src, angle):
    '绕着中心旋转angle度'
    sh, sw = src.shape[0], src.shape[1]
    (cX, cY) = (sw // 2, sh // 2)
    M = getRoteMatrix((int(sw / 2), int(sh / 2)), angle)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])
    nW = int((sh * sin) + (sw * cos))
    nH = int((sh * cos) + (sw * sin))
    dst_sz = (nW, nH)
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY
    # 仿射变换
    dst = cv2.warpAffine(src, M, dst_sz)
    return dst


def getRoteMatrix(rotatePoint, angle):
    '获取相对某点旋转angle度的变换矩阵'
    angle *= np.math.pi / 180
    alpha = np.math.cos(angle)
    beta = np.math.sin(angle)
    M = np.float32([
        [alpha, beta, (1 - alpha) * rotatePoint[0] - beta * rotatePoint[1]],
        [-beta, alpha, beta * rotatePoint[0] + (1 - alpha) * rotatePoint[1]]
    ])
    return M;


# matplotlibShowImg('show_opencv_logo', center_rotate(getImg(), 45))


def official_resize(img):
    height, width = img.shape[0], img.shape[1]
    img = cv2.resize(img, (height * 2, width * 2), interpolation=cv2.INTER_CUBIC)
    matplotlibShowImg("resize 大小变换", img)


def official_translation(img):
    height, width = img.shape[0], img.shape[1]
    M = np.float32([[1, 0, 100], [0, 1, 50]])
    img = cv2.warpAffine(img, M, (height, width))
    matplotlibShowImg("translation变换", img)


def official_rotate(img):
    height, width = img.shape[0], img.shape[1]
    # 第一参数是旋转点，第二个为旋转角度（逆时针），第三个为缩放比例
    M = cv2.getRotationMatrix2D(((height - 1) / 2.0, (height - 1) / 2.0), 90, 2)
    img = cv2.warpAffine(img, M, (height, width))
    matplotlibShowImg("rotate", img)


def official_transform(img):
    """仿射变换是通过三个点在仿射变换后的对应点去计算变换矩阵的"""
    height, width = img.shape[0], img.shape[1]
    pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
    pts2 = np.float32([[10, 100], [200, 50], [100, 250]])
    M = cv2.getAffineTransform(pts1, pts2)
    img = cv2.warpAffine(img, M, (height, width))
    matplotlibShowImg("official_transform", img)


official_resize(getImg())
official_translation(getImg())
official_rotate(getImg())
official_transform(getImg())
